﻿/* 
 * Copyright 2012 Pieter Roggemans
 *
 * This file is part of OWNMonitor.
 *
 * OWNMonitor is free software: you can redistribute it and/or modify it under 
 * the terms of the GNU General Public License as published by the Free Software 
 * Foundation, version 3 of the License.
 *
 * OWNMonitor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with OWNMonitor. 
 * If not, see http://www.gnu.org/licenses/.
 */

/// <summary>
/// OWNMonitor
/// </summary>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BTicino.BtCommLib.Communication;
using BTicino.BtCommLib.Domain.Util;
using BTicino.BtCommLib.Domain.HighLevel;
using System.Text.RegularExpressions;

namespace OWNMonitor
{
    public partial class OWNMonitor : Form
    {
        private IBTCommChan commChannel = null;

        private OWNLib.OWNMessage commHelper;
        private OWNLib.OWNProject openedProject;
        private OWNLib.OWNLogger logger {get; set; }
        private string openedProjectFileName = "C:\\Temp\\OWNProjectData\\Hairgracht16a.xml";

        private String connected = "Connected";
        private String disConnected = "Disconnected";

        delegate void LogFrameCallback(string direction, string frame);
        delegate void LogMsgCallback(string frame);

        delegate void LogEventStatusCallback(string direction, DefaultMsgEventStatus eventStatus);
        delegate void LogEventStatusDimensionCallback(string direction, DefaultMsgEventStatusDimension eventStatus);

#region "Initialisation, onclose,..."

        public OWNMonitor()
        {
            InitializeComponent();
            checkBoxYNBindingSource1.Add(new HelperClasses.CheckBoxYN());
            checkBoxYNBindingSource2.Add(new HelperClasses.CheckBoxYN());
            checkBoxYNBindingSource3.Add(new HelperClasses.CheckBoxYN());

            logger = new OWNLib.OWNLogger();
            loggingBindingSource.DataSource = logger.Logging;

            commHelper = new OWNLib.OWNMessage();
            
            // Try if the last used project can be loaded, otherwise new project...
            try
            {
                openedProject = new OWNLib.OWNProject();
                OWNLib.OWNProject project = OWNLib.OWNProject.LoadXml(openedProjectFileName);

                if (project != null)
                    openedProject = project;
                else
                    openedProject = new OWNLib.OWNProject();
                
                OWNLib.OWNMessage.ProjectData = openedProject;
            }
            catch (Exception ex)
            {
            }

            whosBindingSource.DataSource = OWNLib.OWNMessage.RefData.Whos; 
            wheresBindingSource.DataSource = openedProject.Wheres;
            whatsBindingSource.DataSource = OWNLib.OWNMessage.RefData.WhatsFiltered;
            
            connect();
        }

#endregion

#region "General events to be handled..."

        private void comboBoxWhere_SelectedIndexChanged(object sender, EventArgs e)
        {
            OWNLib.Where where = (OWNLib.Where)comboBoxWhere.SelectedItem;
            if(where != null)
                OWNLib.OWNMessage.RefData.SetFilterWhat(where.WhoId);
        }

#endregion

#region "Private helper functions"

        private void connect()
        {
            // Check if the IP and port aren't empty...
            if (string.IsNullOrEmpty(openedProject.IpAddress))
                return;
            else if (openedProject.IpPort == 0)
                return;
            
            // Get Command Manager Instance
            BTCommMgr cmdMgr = BTCommMgr.Instance;

            if (commChannel == null || !commChannel.isConnected())
            {
                //Get Open Command Channel
                commChannel = (BTOpenCommChan)cmdMgr.getCommChan(BTChanTypes.Open);
                //Handle Events
                commChannel.HandleEvent(BTOpenEventMsgType.EventStatus, typeof(DefaultMsgEventStatus)); //MyMessageEvent<XXX>
                commChannel.HandleEvent(BTOpenEventMsgType.EventStatusDimension, typeof(DefaultMsgEventStatusDimension)); //MyMessageDimensionEvent<XXX>

                //Event/Error Registration
                commChannel.notifyEvent += new IBTCommChan.NotifyEvent(OnEventReceived);
                commChannel.notifyError += new IBTCommChan.NotifyError(OnErrorReceived);
            }

            BTCommChanPar connPar = new BTCommChanPar();
            connPar.setConnPar("IP", openedProject.IpAddress);
            connPar.setConnPar("PORT", openedProject.IpPort.ToString());

            if (openedProject.MonitorOnly)
                connPar.setConnPar("MODE", "RO");
            else
                connPar.setConnPar("MODE", "RW");

            BTCommErr theErr = commChannel.connect(connPar);

            if (theErr.isErr())
                logError(theErr.ErrMsg);
            else
                labelStatus.Text = connected;
        }

        private void disconnect()
        {
            if (commChannel != null)
            {
                commChannel.disconnect();
                labelStatus.Text = disConnected;

                //Remove All Events
                commChannel.RemoveAllHandleEvents();

                //Event/Error DeRegistration
                commChannel.notifyEvent -= new IBTCommChan.NotifyEvent(OnEventReceived);
                commChannel.notifyError -= new IBTCommChan.NotifyError(OnErrorReceived);
            }
        }

#endregion

#region "Button event handlers"

        private void cleanOwnLog_clk(object sender, EventArgs e)
        {
            logger.Logging.Clear();
        }

        private void exitApp_clk(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void buttonSendMessage_Click(object sender, EventArgs e)
        {
            if ((commChannel == null) || (commChannel.isConnected() == false))
            {
                logError("Gateway Disconnected");
                return;
            }
            BTCommErr theErr;
            List<string> outResult;

            DefaultMsgRequest req = new DefaultMsgRequest();
            req.Who = ((OWNLib.Where)comboBoxWhere.SelectedItem).WhoId;
            req.What = (string)comboBoxWhat.SelectedValue;
            req.Where = ((OWNLib.Where)comboBoxWhere.SelectedItem).WhereId;

            theErr = commChannel.Send(req);
            if (!theErr.isErr())
            {
//                    logFrame("0", textBoxFrame.Text);
//                    logFrames("1", outResult);
            }
            else
            {
                logError(theErr.ErrMsg);
            }
        }

        private void buttonSendFrame_clk(object sender, EventArgs e)
        {
            if ((commChannel == null) || (commChannel.isConnected() == false))
            {
                logError("Gateway Disconnected");
                return;
            }

            BTCommErr theErr;
            List<string> outResult;
            string theFrame = textBoxFrame.Text;
            if (!isAValidOpenFrame(theFrame))
                logError("Invalid Frame ");
            else
            {
                theErr = commChannel.Send(textBoxFrame.Text, out outResult);
                if (!theErr.isErr())
                {
//                    logFrame("0", textBoxFrame.Text);
//                    logFrames("1", outResult);
                }
                else
                {
                    logError(theErr.ErrMsg);
                }
            }
        }

        private void buttonCleanFilterLog_Click(object sender, EventArgs e)
        {
            textBoxFilter.Clear();
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            if (comboBoxFilter.Items.Contains(comboBoxFilter.Text))
            {
                return;
            }
            else
            {
                comboBoxFilter.Items.Add(comboBoxFilter.Text);
            }
        }

        private void buttonRemove_Click(object sender, EventArgs e)
        {
            if (comboBoxFilter.Items.Contains(comboBoxFilter.Text))
            {
                comboBoxFilter.Items.Remove(comboBoxFilter.Text);
            }
        }

#endregion

#region "Handling of toolstripMenu events..."

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void configureYourInstallationToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void editProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProjectForm configureProject = new ProjectForm(
                OWNLib.OWNMessage.RefData, OWNLib.OWNMessage.ProjectData,
                openedProjectFileName);

            configureProject.ShowDialog();
        }

#endregion

#region "Handling of monitoring events..."

        public void OnEventReceived(object eventMsg)
        {

            if (eventMsg is DefaultMsgEventStatus)
            {

                DefaultMsgEventStatus mmes = (DefaultMsgEventStatus)eventMsg;
                logEventStatus("3", mmes);
            }
            else
            {
                DefaultMsgEventStatusDimension mmes = (DefaultMsgEventStatusDimension)eventMsg;
                logEventStatusDimension("3", mmes);
            }
        }

        public void OnErrorReceived(BTCommErr errorMsg)
        {
        }

        private void logEventStatus(string direction, DefaultMsgEventStatus frameEventStatus)
        {
            //  Handle the thread safe Windows Form controll access
            //  since this service could be called by a thread that
            //  is different from the thread that creates the GUI Object
            if (this.dataGridViewLog.InvokeRequired)
            {
                LogEventStatusCallback d = new LogEventStatusCallback(logEventStatus);
                this.Invoke(d, new object[] { direction, frameEventStatus });
                return;
            }

            if (mustBeLogged(direction))
            {
                logger.Logging.Add(new OWNLib.OWNLogLine(new OWNLib.OWNMessage.MsgEventStatus(direction, frameEventStatus)));

                if (Regex.IsMatch(frameEventStatus.OpenRawMsg, comboBoxFilter.Text))
                {
                    string message = commHelper.PrintMsgEventStatus(direction, frameEventStatus);
                    this.textBoxFilter.AppendText(DateTime.Now + "   " + message + "\r\n");
                }
            }
        }

        private void logEventStatusDimension(string direction, DefaultMsgEventStatusDimension frameEventStatusDim)
        {
            //  Handle the thread safe Windows Form controll access
            //  since this service could be called by a thread that
            //  is different from the thread that creates the GUI Object
            if (this.dataGridViewLog.InvokeRequired)
            {
                LogEventStatusDimensionCallback d = new LogEventStatusDimensionCallback(logEventStatusDimension);
                this.Invoke(d, new object[] { direction, frameEventStatusDim });
                return;
            }

            if (mustBeLogged(direction))
            {
                OWNLib.OWNMessage.MsgEventStatusDimension dim = new OWNLib.OWNMessage.MsgEventStatusDimension(direction, frameEventStatusDim);
                logger.Logging.Add(new OWNLib.OWNLogLine(dim));

                if (Regex.IsMatch(frameEventStatusDim.OpenRawMsg, comboBoxFilter.Text))
                {
                    string message = commHelper.PrintMsgEventStatusDimension(direction, frameEventStatusDim);
                    this.textBoxFilter.AppendText(DateTime.Now + "   " + message + "\r\n");
                }
            }
        }

        private void logError(string theErrMsg)
        {
            logger.Logging.Add(new OWNLib.OWNLogLine("ERROR: " + theErrMsg));
            if (Regex.IsMatch(theErrMsg, comboBoxFilter.Text))
            {
                textBoxFilter.AppendText(DateTime.Now + "   " + "ERROR: " + theErrMsg + "\r\n");
            }
        }

        private Boolean mustBeLogged(string direction)
        {
            //  Logging Is Switched off
            if (!checkBoxEnabLog.Checked)
                return false;

            switch (direction)
            {
                case "3":           // Monitoring
                    if (checkBoxMonLog.Checked)
                        return true;
                    break;
                case "1":           // Rx
                    if (checkBoxComLog.Checked)
                        return true;
                    break;
                case "0":           // Tx
                    if (checkBoxComLog.Checked)
                        return true;
                    break;
                default:
                    break;
            }

            return false;
        }

        private bool isAValidOpenFrame(string theFrame)
        {
            bool retCode = true;

            if ((theFrame == null) ||
                (theFrame.Length == 0) ||
                (!theFrame.Contains('*')) ||
                (!theFrame.EndsWith("##"))
            )
                retCode = false;

            return (retCode);
        }
    }

#endregion

}
